package com.young.shop.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.young.common.AdminConstant;
import com.young.domain.SysMenu;
import com.young.domain.SysMenuExample;
import com.young.domain.SysRoleMenu;
import com.young.domain.SysRoleMenuExample;
import com.young.domain.SysUserRole;
import com.young.domain.SysUserRoleExample;
import com.young.domain.SysUserRoleExample.Criteria;
import com.young.mapper.SysMenuMapper;
import com.young.mapper.SysRoleMenuMapper;
import com.young.mapper.SysUserRoleMapper;
import com.young.req.AddMenuReq;
import com.young.res.SysMenuRolePermRes;
import com.young.res.vo.AuthVo;
import com.young.res.vo.MenuVo;
import com.young.shop.service.SysMenuService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Description: 菜单，权限，角色服务类
 * @Author: kangyang
 * @Date: 2021/5/14 11:08
 **/
@Service
public class SysMenuServiceImpl implements SysMenuService {

  private Logger log = LoggerFactory.getLogger(SysMenuServiceImpl.class);

  @Autowired
  private SysUserRoleMapper sysUserRoleMapper;

  @Autowired
  private SysRoleMenuMapper sysRoleMenuMapper;

  @Autowired
  private SysMenuMapper sysMenuMapper;

  @Autowired
  private RedisTemplate redisTemplate;


  @Override
  @Cacheable(cacheNames = "com.young.res.SysMenuRolePermRes", key = "#userId")
  public SysMenuRolePermRes getMenuRolePerm(Long userId) {
    log.info("查询菜单，权限，角色信息开始, 用户Id->{}", userId);
    if (userId == null) {
      return null;
    }
    Object o = redisTemplate.opsForValue().get("com.young.res.SysMenuRolePermRes#" + userId);
    if (o != null) {
      SysMenuRolePermRes sysMenuRole = JSONObject
          .parseObject((String) o, SysMenuRolePermRes.class);
      if (sysMenuRole != null) {
        return sysMenuRole;
      }
    }
    SysUserRoleExample sysUserRoleExample = new SysUserRoleExample();
    Criteria userRoleCriteria = sysUserRoleExample.createCriteria();
    userRoleCriteria.andUserIdEqualTo(userId);
    userRoleCriteria.andIsDeleteEqualTo(Boolean.FALSE);
    List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectByExample(sysUserRoleExample);
    List<Long> roleIds = new ArrayList<>();
    if (CollectionUtils.isNotEmpty(sysUserRoles)) {
      sysUserRoles.forEach(userRole -> {
        roleIds.add(userRole.getRoleId());
      });
    }

    SysMenuRolePermRes sysMenuRolePermRes = new SysMenuRolePermRes();
    SysRoleMenuExample sysRoleMenuExample = new SysRoleMenuExample();
    SysRoleMenuExample.Criteria roleMenuCriteria = sysRoleMenuExample.createCriteria();
    roleMenuCriteria.andRoleIdIn(roleIds);
    roleMenuCriteria.andIsDeleteEqualTo(Boolean.FALSE);
    List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectByExample(sysRoleMenuExample);
    List<Long> menuId = sysRoleMenus.stream().filter(s -> s != null).map(SysRoleMenu::getMenuId)
        .distinct()
        .collect(Collectors.toList());
    SysMenuExample sysMenuExample = new SysMenuExample();
    SysMenuExample.Criteria sysMenuCriteriariteria = sysMenuExample.createCriteria();
    sysMenuCriteriariteria.andMenuIdIn(menuId);
    sysMenuCriteriariteria.andIsDeleteEqualTo(Boolean.FALSE);
    sysMenuExample.setOrderByClause("order_num");
    List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
    List<MenuVo> menuVos = createMenuVo(sysMenus);
    List<AuthVo> authVos = createAuthVo(sysMenus);
    redisTemplate.opsForValue().set(AdminConstant.AUTH_PERMISSION_PRE + userId,
        JSONArray.toJSONString(authVos));
    sysMenuRolePermRes.setMenuList(menuVos);
    sysMenuRolePermRes.setAuthorities(authVos);
    redisTemplate.opsForValue().set("com.young.res.SysMenuRolePermRes#" + userId,
        JSONObject.toJSONString(sysMenuRolePermRes), 24,
        TimeUnit.HOURS);
    log.info("查询菜单，权限，角色信息结束, 用户Id->{}, 返回参数->{}", userId,
        JSONObject.toJSONString(sysMenuRolePermRes));
    return sysMenuRolePermRes;
  }

  @Override
  public List<SysMenu> getAllMenu() {
    SysMenuExample sysMenuExample = new SysMenuExample();
    SysMenuExample.Criteria sysMenuExampleCriteria = sysMenuExample.createCriteria();
    sysMenuExampleCriteria.andIsDeleteEqualTo(Boolean.FALSE);
    sysMenuExample.setOrderByClause("order_num");
    List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
    return sysMenus;
  }

  @Override
  public Boolean inserMenu(AddMenuReq addMenuReq) {
    if (addMenuReq != null) {
      SysMenu sysMenu = new SysMenu();
      BeanUtils.copyProperties(addMenuReq, sysMenu);
      sysMenu.setMenuId(new Date().getTime());
      sysMenuMapper.insertSelective(sysMenu);
    }
    return Boolean.TRUE;
  }

  @Override
  public SysMenu getMenuByMenuId(Long menuId) {
    SysMenuExample sysMenuExample = new SysMenuExample();
    SysMenuExample.Criteria sysMenuExampleCriteria = sysMenuExample.createCriteria();
    sysMenuExampleCriteria.andMenuIdEqualTo(menuId);
    List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
    if(CollectionUtils.isNotEmpty(sysMenus)) {
      return sysMenus.get(0);
    }
    return new SysMenu();
  }

  @Override
  public Boolean updateMenuInfo(AddMenuReq addMenuReq) {
    SysMenu sysMenu = new SysMenu();
    BeanUtils.copyProperties(addMenuReq, sysMenu);
    int i = sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
    return Boolean.TRUE;
  }

  @Override
  @Transactional
  public Boolean deleteMenu(Long menuId) {
    if(menuId == null) {
      return false;
    }
    // 如果有子节点，则不能删除
    SysMenuExample sysMenuExample = new SysMenuExample();
    SysMenuExample.Criteria sysMenuExampleCriteria = sysMenuExample.createCriteria();
    sysMenuExampleCriteria.andParentIdEqualTo(menuId);
    List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
    if(CollectionUtils.isNotEmpty(sysMenus)) {
      throw new RuntimeException("该菜单还有子菜单，不能删除");
    }
    SysMenu sysMenu = new SysMenu();
    sysMenu.setMenuId(menuId);
    sysMenu.setIsDelete(Boolean.TRUE);
    sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
    sysRoleMenuMapper.deleteByMenuId(menuId);
    return Boolean.TRUE;
  }

  /**
   * @return java.util.List<com.young.res.vo.MenuVo>
   * @Author kangyang
   * @Description 构建菜单树
   * @Date 12:44 2021/5/14
   * @Param [sysMenus]
   **/
  private List<MenuVo> createMenuVo(List<SysMenu> sysMenus) {
    List<MenuVo> menuVos = new ArrayList<>();
    if (CollectionUtils.isEmpty(sysMenus)) {
      return menuVos;
    }
    List<SysMenu> rootMenus = sysMenus.stream()
        .filter(s -> s != null && Long.valueOf(0).equals(s.getParentId()))
        .collect(Collectors.toList());
    if (CollectionUtils.isNotEmpty(rootMenus)) {
      rootMenus.stream().forEach(rootMenu -> {
        MenuVo menuVo = new MenuVo();
        menuVo.setMenuId(rootMenu.getMenuId());
        menuVo.setName(rootMenu.getName());
        menuVo.setUrl(rootMenu.getUrl());
        List<MenuVo> menuVoList = new ArrayList<>();
        sysMenus.stream().forEach(menu -> {
          if (menu.getParentId() != null && menu.getParentId().equals(rootMenu.getMenuId())) {
            MenuVo secondMenu = new MenuVo();
            secondMenu.setMenuId(menu.getMenuId());
            secondMenu.setName(menu.getName());
            secondMenu.setUrl(menu.getUrl());
            menuVoList.add(secondMenu);
          }
        });
        menuVo.setList(menuVoList);
        menuVos.add(menuVo);
      });
    }
    return menuVos;
  }

  private List<AuthVo> createAuthVo(List<SysMenu> sysMenus) {
    List<AuthVo> authVos = new ArrayList<>();
    if (CollectionUtils.isEmpty(sysMenus)) {
      return authVos;
    }

    sysMenus.stream()
        .filter(sysMenu -> sysMenu != null && StringUtils.isNotEmpty(sysMenu.getPerms()))
        .forEach(sysMenu -> {
          String perm = sysMenu.getPerms();
          List<String> perms = (List<String>) Arrays.asList(perm.split(","));
          perms.forEach(p -> {
            AuthVo authVo = new AuthVo();
            authVo.setAuthority(p);
            authVos.add(authVo);
          });
        });

    return authVos;
  }


}
